import 'dart:async';

import 'package:amap_map_fluttify/amap_map_fluttify.dart';
import 'package:async/async.dart';
import 'package:boss/color_constant.dart';

import 'package:boss/textStyle/text_style.dart';
import 'package:boss/ui/widget/alert/alert.dart';
import 'package:boss/ui/widget/back_confirmation.dart';
import 'package:boss/ui/widget/button/radius_button.dart';
import 'package:boss/ui/widget/center_title_app_bar.dart';
import 'package:boss/ui/widget/form/base_text_form_field.dart';
import 'package:boss/ui/widget/image/base_image.dart';
import 'package:hi_common/hi_common.dart';
import 'package:city_pickers/city_pickers.dart' as cityPicker;
import 'package:flustars/flustars.dart' as flustars;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:vector_math/vector_math_64.dart' as v;

class PCDHData {
  String provinces;
  String provincesCode;
  String city;
  String cityCode;
  String address;
  String district;
  String districtCode;
  String houseNumber;
  double latitude;
  double longitude;

  PCDHData({
    this.provinces,
    this.provincesCode,
    this.city,
    this.cityCode,
    this.address,
    this.district,
    this.districtCode,
    this.houseNumber,
    this.latitude,
    this.longitude,
  });
}

Future<PCDHData> showPickerAddressPage(BuildContext context, {PCDHData data}) {
  return Navigator.push<PCDHData>(
    context,
    MaterialPageRoute(
      builder: (context) => PickerAddressPage(data: data),
    ),
  );
}

class PickerAddressPage extends StatefulWidget {
  final PCDHData data;

  const PickerAddressPage({this.data});

  @override
  _PickerAddressPageState createState() => _PickerAddressPageState();
}

class _PickerAddressPageState extends State<PickerAddressPage> with TickerProviderStateMixin {
  String provinces;
  String provincesCode;
  String city;
  String cityCode;
  String address;
  String district;
  String districtCode;
  String houseNumber;
  String title;
  double latitude;
  double longitude;

  AmapController amapController;

  AnimationController animationController;

  Animation<double> contentAni;

  Animation<double> searchBarAni;

  double endTop = 0;

  double beginTop = 0;

  double searchBarHeight = 0;

  List<Poi> poiList;

  List<Poi> inputTipList;

  FocusNode searchFocusNode = FocusNode();

  TextEditingController searchContainer = TextEditingController();

  CancelableOperation cancelableOperation;

  GlobalKey moveDotKey = GlobalKey();

  AnimationController moveDotAniCon;

  Animation<double> moveDotAni;
  Animation<double> moveDotShadowAni;

  Timer timer;

  @override
  void initState() {
    super.initState();

    moveDotAniCon = AnimationController(duration: Duration(milliseconds: 300), vsync: this)
      ..addListener(() {
        setState(() {});
      });
    moveDotAni = Tween(begin: 0.0, end: -8.0).animate(moveDotAniCon);
    moveDotShadowAni = Tween(begin: 0.0, end: 10.0).animate(moveDotAniCon);

    animationController = AnimationController(duration: Duration(milliseconds: 300), vsync: this)
      ..addListener(() {
        setState(() {});
      });

    searchBarAni = Tween(begin: 0.0, end: 1.0).animate(animationController);

    searchFocusNode.addListener(searchBarFocusChanged);

    if (widget.data != null) {
      if (widget.data.address.contains('|')) {
        final split = widget.data.address.split('|');
        address = split[0];
        title = split[1];
      } else {
        address = widget.data.address;
        title = '';
      }

      provinces = widget.data.provinces;
      provincesCode = widget.data.provincesCode;
      city = widget.data.city;
      cityCode = widget.data.cityCode;
      district = widget.data.district;
      districtCode = widget.data.districtCode;
      houseNumber = widget.data.houseNumber;
      latitude = widget.data.latitude;
      longitude = widget.data.longitude;
    }
  }

  @override
  void dispose() {
    moveDotAniCon.dispose();
    animationController.dispose();
    amapController.dispose();
    searchFocusNode.dispose();
    searchContainer.dispose();

    if (timer != null) timer.cancel();

    if (cancelableOperation != null) cancelableOperation.cancel();

    super.dispose();
  }

  searchAround(LatLng latLng, {String keyword, String city}) async {
    if (latLng == null) return;

    poiList = await AmapSearch.instance.searchAround(
      latLng,
      keyword: keyword ?? '',
      city: city ?? '',
    );
    if (mounted) setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    beginTop = 60.w;
    searchBarHeight = 130.w;

    final screenHeight = MediaQuery.of(context).size.height;
    endTop = screenHeight - (screenHeight - searchBarHeight) / 2;

    final curvedAnimation = CurvedAnimation(parent: animationController, curve: Curves.easeIn);

    contentAni = Tween(begin: beginTop, end: endTop).animate(curvedAnimation);

    return BackConfirmation(
      backConfirmationText: '确定要放弃此次编辑？',
      child: Scaffold(
        backgroundColor: Colors.white,
        resizeToAvoidBottomInset: false,
        appBar: CenterTitleAppBar(
          title: '地址选择',
          isShowDivider: false,
          backConfirmationText: '确定要放弃此次编辑？',
        ),
        body: Container(
          width: double.infinity,
          height: double.infinity,
          child: Stack(
            alignment: Alignment.center,
            children: [
              buildMap(),
              buildLocalMoveDot(),
              buildSearchBar(),
              buildContent(),
              if (inputTipList != null && inputTipList.length > 0) buildSearchTipList(),
            ],
          ),
        ),
      ),
    );
  }

  Widget buildMap() {
    return Positioned(
      top: 0,
      left: 0,
      right: 0,
      child: Container(
        height: endTop,
        child: AmapView(
          // 地图类型 (可选)
          mapType: MapType.Standard,
          // 是否显示缩放控件 (可选)
          showZoomControl: false,
          // 是否显示指南针控件 (可选)
          showCompass: false,
          // 是否显示比例尺控件 (可选)
          showScaleControl: true,
          // 是否使能缩放手势 (可选)
          zoomGesturesEnabled: true,
          // 是否使能滚动手势 (可选)
          scrollGesturesEnabled: true,
          // 是否使能旋转手势 (可选)
          rotateGestureEnabled: true,
          // 是否使能倾斜手势 (可选)
          tiltGestureEnabled: true,
          // 缩放级别 (可选)
          zoomLevel: 16,
          // 地图创建完成回调 (可选)
          onMapCreated: onMapCreated,
          onMapMoveStart: onMapMoveStart,
          onMapMoveEnd: onMapMoveEnd,
        ),
      ),
    );
  }

  Widget buildSearchBar() {
    return Positioned(
      top: 0,
      left: 0,
      right: 0,
      child: FadeTransition(
        opacity: searchBarAni,
        child: Container(
          height: searchBarHeight,
          padding: EdgeInsets.symmetric(horizontal: 20.w),
          decoration: BoxDecoration(color: Colors.white),
          alignment: Alignment.center,
          child: Container(
            height: 70.w,
            padding: EdgeInsets.symmetric(horizontal: 20.w),
            decoration: BoxDecoration(
              border: Border.all(color: ColorConstant.ffcc, width: 1.px),
              borderRadius: BorderRadius.circular(70.w),
            ),
            child: Row(
              children: [
                InkWell(
                  onTap: pickerCity,
                  child: Row(
                    children: [
                      Text('$city', style: TextStyle(fontSize: 28.sp, color: ColorConstant.ff33)),
                      Icon(Icons.arrow_drop_down, size: 28.sp, color: ColorConstant.ff99)
                    ],
                  ),
                ),
                Container(
                  width: 1.px,
                  height: 30.w,
                  color: ColorConstant.ffcc,
                  margin: EdgeInsets.symmetric(horizontal: 24.w),
                ),
                BaseImage(
                  'assets/image/address_search_icon.png',
                  width: 40.w,
                  height: 40.w,
                ),
                Expanded(
                  child: Container(
                    alignment: Alignment.center,
                    margin: EdgeInsets.only(left: 10.w),
                    child: TextField(
                      controller: searchContainer,
                      focusNode: searchFocusNode,
                      textAlignVertical: TextAlignVertical.center,
                      style: TextStyle(fontSize: 26.sp, color: ColorConstant.ff33),
                      decoration: InputDecoration(
                        isDense: true,
                        contentPadding: EdgeInsets.zero,
                        hintText: '请输入地址寻找周边门店',
                        counterText: '',
                        hintStyle: TextStyle(fontSize: 26.sp, color: ColorConstant.ffcc),
                        border: NoInputBorder(),
                        disabledBorder: NoInputBorder(),
                        enabledBorder: NoInputBorder(),
                        errorBorder: NoInputBorder(),
                        focusedBorder: NoInputBorder(),
                        focusedErrorBorder: NoInputBorder(),
                      ),
                      onChanged: searchWordAround,
                    ),
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }

  Widget buildContent() {
    return Positioned(
      top: contentAni?.value ?? beginTop,
      left: 0,
      right: 0,
      bottom: 0,
      child: Container(
        decoration: BoxDecoration(
          color: Colors.white,
          borderRadius: BorderRadius.circular(10),
        ),
        padding: EdgeInsets.symmetric(horizontal: 25.w, vertical: 20.w),
        child: animationController.isCompleted ? buildPoiContent() : buildMessageContent(),
      ),
    );
  }

  Widget buildMessageContent() {
    final primaryColor = Theme.of(context).primaryColor;

    return Column(
      children: [
        if (address != null)
          Container(
            child: ListTile(
              title: Text('$title', maxLines: 1, overflow: TextOverflow.ellipsis),
              subtitle: Text('$address', maxLines: 1, overflow: TextOverflow.ellipsis),
              trailing: OutlineButton(
                child: Text('修改地址'),
                onPressed: slideDown,
              ),
            ),
          ),
        if (address == null)
          InkWell(
            onTap: slideDown,
            child: Container(
              height: 80.w,
              decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(10),
                border: Border.all(color: primaryColor, width: 1.px),
              ),
              alignment: Alignment.center,
              child: Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Text(
                    '选择地址',
                    style: TextStyle(
                      color: primaryColor,
                      fontSize: 24.sp,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                  Icon(
                    Icons.chevron_right,
                    size: 26.sp,
                    color: primaryColor,
                  ),
                ],
              ),
            ),
          ),
        SizedBox(height: 20.w),
        BaseTextFormField(
          prefixText: '门牌号',
          hintText: '详细地址，例1层101室',
          initialValue: houseNumber,
          onChanged: houseNumberChanged,
        ),
        SizedBox(height: 20.w),
        RadiusButton(
          width: double.infinity,
          height: 80.w,
          title: '保存地址',
          onTap: confirm,
        )
      ],
    );
  }

  Widget buildPoiContent() {
    return ListView.builder(
      padding: EdgeInsets.zero,
      itemBuilder: (context, index) {
        return buildPoiItem(poiList[index]);
      },
      itemCount: poiList?.length ?? 0,
    );
  }

  Widget buildSearchTipList() {
    return Positioned.fill(
      top: searchBarHeight,
      child: Container(
        decoration: BoxDecoration(
          color: Colors.white,
        ),
        child: ListView.builder(
          padding: EdgeInsets.zero,
          itemBuilder: (context, index) {
            return buildPoiItem(inputTipList[index]);
          },
          itemCount: inputTipList?.length ?? 0,
        ),
      ),
    );
  }

  Widget buildPoiItem(Poi poi) {
    final current = poi;
    final address = '$provinces${current.adName}${current.address}';

    return GestureDetector(
      onTap: () async {
        searchFocusNode.unfocus();

        provinces = current.provinceName;
        city = current.cityName;
        district = current.adName ?? city;
        this.address = current.address;
        title = current.title;

        provincesCode = current.provinceCode;
        cityCode = current.cityCode;
        districtCode = current.adCode ?? cityCode;

        longitude = current.latLng.longitude;
        latitude = current.latLng.latitude;

        inputTipList = [];

        amapController.setCenterCoordinate(current.latLng);

        slideUp();
      },
      child: Container(
        padding: EdgeInsets.symmetric(vertical: 20.w),
        decoration: BoxDecoration(
          border: Border(
            bottom: BorderSide(
              color: ColorConstant.e6e6,
              width: 1.px,
            ),
          ),
        ),
        child: Row(
          children: [
            Container(
              margin: EdgeInsets.only(right: 20.w),
              child: BaseImage(
                'assets/image/address_dot.png',
                width: 30.w,
                height: 30.w,
              ),
            ),
            Expanded(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Row(
                    children: [
                      Expanded(
                        child: Text(
                          current.title,
                          style: TextStyleConstant().normal_1_30,
                          maxLines: 1,
                          overflow: TextOverflow.ellipsis,
                        ),
                      ),
                      Container(
                        width: 100.w,
                        alignment: Alignment.center,
                        child: Text(int2mOrKm(current.distance), style: TextStyleConstant().normal_3_30),
                      )
                    ],
                  ),
                  Container(
                    margin: EdgeInsets.only(top: 10.w),
                    child: Text(
                      address,
                      style: TextStyleConstant().normal_3_26,
                      maxLines: 2,
                      overflow: TextOverflow.ellipsis,
                    ),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }

  Widget buildLocalMoveDot() {
    final top = endTop / 2 - 50.w / 2 - 22.w / 2;
    return Positioned(
      top: top,
      key: moveDotKey,
      child: Stack(
        alignment: Alignment.center,
        overflow: Overflow.visible,
        children: [
          Container(
            transform: Matrix4.translation(v.Vector3(0, moveDotAni.value, 0)),
            child: BaseImage(
              'assets/image/local_move_dot.png',
              width: 28.w,
              height: 50.w,
            ),
          ),
          Positioned(
            bottom: -5,
            child: Container(
              width: moveDotShadowAni.value,
              height: moveDotShadowAni.value,
              transform: Matrix4.rotationX(1),
              decoration: BoxDecoration(
                color: Colors.black26,
                shape: BoxShape.circle,
              ),
            ),
          ),
        ],
      ),
    );
  }

  Future<void> onMapMoveStart(MapMove move) async {
    moveDotAniCon.forward();
  }

  Future<void> onMapMoveEnd(MapMove move) async {
    moveDotAniCon.reverse();

    searchAround(move.latLng);
  }

  void slideDown() {
    if (animationController.isAnimating) return;

    searchContainer.value = TextEditingValue.empty;

    animationController.forward();
  }

  void slideUp() {
    if (animationController.isAnimating) return;

    animationController.reverse();
  }

  void searchWordAround(String value) async {
    if (timer?.isActive ?? false) {
      timer?.cancel();
    }
    timer = Timer(Duration(milliseconds: 300), () async {
      inputTipList = await AmapSearch.instance.searchKeyword(value, city: city);
      if (mounted) setState(() {});
    });
  }

  Future<void> onMapCreated(AmapController controller) async {
    amapController = controller;

    LatLng latLng;
    if (longitude != null && latitude != null) {
      latLng = LatLng(latitude, longitude);
    } else {
      final isGranted = await Permission.locationWhenInUse.isGranted;
      if (isGranted) {
        final location = await AmapLocation.instance.fetchLocation();
        setLocation(location);
        latLng = LatLng(location.latLng.latitude, location.latLng.longitude);
      } else {
        final permissionStatus = await Permission.locationWhenInUse.request();

        if (permissionStatus.isGranted) {
          final location = await AmapLocation.instance.fetchLocation();
          setLocation(location);

          latLng = LatLng(location.latLng.latitude, location.latLng.longitude);
        }
      }
    }
    latitude = latLng.latitude;
    longitude = latLng.longitude;

    await amapController.setCenterCoordinate(latLng, animated: false);

    await amapController.addMarker(
      MarkerOption(
        coordinate: latLng,
        iconProvider: AssetImage('assets/image/local_dot.png'),
      ),
    );
  }

  void setLocation(Location location) {
    provinces = location.province;
    city = location.city;
    setState(() {});
  }

  void searchBarFocusChanged() {
    if (!searchFocusNode.hasFocus) {
      setState(() {
        inputTipList = [];
      });
    }
  }

  void pickerCity() async {
    var result = await cityPicker.CityPickers.showCitiesSelector(
      context: context,
      theme: ThemeData(
        appBarTheme: AppBarTheme(
          color: Colors.white,
          iconTheme: IconThemeData(color: ColorConstant.ff33),
          textTheme: TextTheme(headline6: TextStyleConstant().normal_1_28),
        ),
      ),
    );

    if (result != null) {
      var util = cityPicker.CityPickers.utils();
      result = util.getAreaResultByCode(result.cityId);

      provinces = result.provinceName;
      provincesCode = result.provinceId;
      city = result.cityName;
      cityCode = result.cityId;
      address = null;
      title = null;
      district = null;
      districtCode = null;
      setState(() {});

      final geoList = await AmapSearch.instance.searchGeocode(city, city: city);
      final latLng = geoList[0].latLng;

      amapController.setCenterCoordinate(latLng);
    }
  }

  void confirm() {
    if (address == null) {
      toast('请选择地址');
      return;
    }
    if (flustars.TextUtil.isEmpty(houseNumber)) {
      toast('请输入门牌号');
      return;
    }

    Navigator.pop(
        context,
        PCDHData(
          provinces: provinces,
          provincesCode: provincesCode,
          city: city,
          cityCode: cityCode,
          district: district,
          districtCode: districtCode,
          address: address + '|' + title,
          houseNumber: houseNumber,
          latitude: latitude,
          longitude: longitude,
        ));
  }

  void onPoiTap(Poi value) {
    searchFocusNode.unfocus();

    provinces = value.provinceName;
    city = value.cityName;
    this.address = value.address;
    district = value.adName;

    title = value.title;

    provincesCode = value.provinceCode;
    cityCode = value.cityCode;
    districtCode = value.adCode;

    latitude = value.latLng.latitude;
    longitude = value.latLng.longitude;

    inputTipList = [];

    amapController.setCenterCoordinate(value.latLng);

    slideUp();
  }

  void houseNumberChanged(String value) async {
    houseNumber = value;
  }

  String int2mOrKm(int value) {
    if (value < 1000) {
      return '${value}m';
    }

    return '${value / 1000.0}km';
  }
}
